package AP;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Vector;

public class MobileAgent implements Runnable, Persistent{
	
	private static final int NULL = 0;
	private static final int CONTACT = 1;
	private static final int TIME = 2;
	private static final int BOOL = 3;
	private static final int LENGTH = 4;

	private Vector contacts;    //string
	private Vector times;       //string
	private int length;			//minutes
	private boolean[][] available;
       
	/*constructor*/
	public MobileAgent(){
		//create and set 4 test contacts
		String contact0 = "Aidan";
		String contact1 = "Jonathan";
		String contact2 = "Francis";
		String contact3 = "Kevin";
		this.contacts.addElement(contact0);
		this.contacts.addElement(contact1);
		this.contacts.addElement(contact2);
		this.contacts.addElement(contact3);
		
		//create and set 3 test times
		String time0 = "11am";
		String time1 = "1pm";
		String time2 = "4pm";
		this.times.addElement(time0);
		this.times.addElement(time1);
		this.times.addElement(time2);
		
		//create and set meeting length
		this.length = 60;
		
		//create and set availability matrix
		//contacts x times + hasReceived
		available = new boolean[this.contacts.size()][this.times.size()+1];
		for(int i=0; i<this.contacts.size(); i++){
			for(int j=0; j<this.times.size()+1; j++){
				if( i==0 )
					this.available[i][j] = true;
				else
					this.available[i][j] = false;
			}				
		}
	}
       
	/**
	 * run method still to be completed
	 **/
	public void run(){}

	/**
	 * return the first contact that has not yet received the agent
	 **/
	public String getNextDest(){
		for(int i=0; i<this.contacts.size(); i++){
			if( this.available[i][0]==false )
				return this.contacts.elementAt(i).toString();
		}
		return "";
	}

	public byte[] persist() throws IOException {       
		ByteArrayOutputStream bout =  new ByteArrayOutputStream();
		DataOutputStream      dout =  new DataOutputStream( bout );
		
		int n = this.contacts.size();
		int m = this.times.size();
		//write out: number of contacts + number of times + number of booleans + length
		dout.writeInt( n+m+(n*(m+1))+1 );
		
		/**
		 * first write out contacts
		 **/
		for( int i = 0; i < n; i++ ){                  
			Object o = this.contacts.elementAt( i );
			if( o instanceof String ){
				dout.writeByte( CONTACT );
				dout.writeUTF( (String) o );
			}
			else if( o == null ){
				dout.writeByte( NULL );
			}
			else {
				throw new IOException("Cannot persist " + "object of type " + o.getClass().getName() );
			}
		}
		/**
		 * then write out times
		 **/
		for( int i = 0; i < m; i++ ){                  
			Object o = this.times.elementAt( i );
			if( o instanceof String ){
				dout.writeByte( TIME );
				dout.writeUTF( (String) o );
			}
			else if( o == null ){
				dout.writeByte( NULL );
			}
			else {
				throw new IOException("Cannot persist " + "object of type " + o.getClass().getName());
			}
		}
		/**
		 * then write out availability
		 **/
		for( int i = 0; i < n; i++ ){     
			for( int j = 0; j < m+1; j++ ){
				dout.writeByte( BOOL );
				dout.writeBoolean(this.available[i][j]);
			}
		}
		/**
		 * then write out length
		 **/
		dout.writeByte( LENGTH );
		dout.writeInt(this.length);
		
		dout.flush();
		
		return bout.toByteArray();      
	}
   
	public void resurrect( byte[] persisted ) throws IOException {
		ByteArrayInputStream bin = new ByteArrayInputStream( persisted );
		DataInputStream      din = new DataInputStream( bin );
		
		int l = din.readInt();
		int i=0, n;//contacts
		int j=0, m;//times
		int type;
		
		//read in all 0 to l-1 elements
		for( int k = 0; k < l; k++ ){
			type = din.readByte();
			
			if( type == CONTACT ){
				this.contacts.addElement( din.readUTF() );
			}
			else if( type == TIME ){
				this.times.addElement( din.readUTF() );
			}
			else if( type == BOOL ){
				n = this.contacts.size();
				m = this.times.size();
				//i & j declared outside loop to allow multiple
				//entries into the loop with index values maintained
				while( i<n && type == BOOL ){
					while( j<m && type == BOOL ){
						this.available[i][j] = din.readBoolean();
						type = din.readByte();
					}
				}
			}			
			else if( type == NULL ){}
			else {
				throw new IOException( "Unknown " + "type " + type );
			}
		}  
	}
}